home *** CD-ROM | disk | FTP | other *** search
- #define USE_PICTS 1 /* 1 if PICTs are to be displayed, 0 for text only */
- #define ONE_RESOURCE 1 /* 1 for Get1Resource, 0 for GetResource, etc. */
- #define COMPRESSION 1 /* compressed TEXT/styl or PICTs */
- #define STANDALONE 1
-
- #define CHECKPOINTS 0
- #define ASSERTIONS 0
-
- #define PREFLIGHT_MEMORY 20000L
-
- #if ASSERTIONS
- #define ASSERT_SET_NIL(lvalue) lvalue = NIL
- #else
- #define ASSERT_SET_NIL(lvalue)
- #endif
-
- #if STANDALONE
- #define Show_help main
- #else
- void main( void );
- #endif
-
- #include "Show_help.h"
- #include "Show_help typedefs.h"
-
- /*
- Show_help by James W. Walker, June 1991
-
- version 2.0, updated July 1992
-
- This code is freely usable. If you want to show your gratitude,
- you could send me a free copy of whatever program you develop
- with it.
-
- e-mail:
- Internet 76367.2271@compuserve.com
- CIS 76367,2271
- America Online JWWalker
-
- This code displays scrolling text in a dialog box. The text comes
- from TEXT/styl resources, which can be created with ResEdit 2.1 or
- with an accompanying HyperCard stack.
- The text cannot be edited, but one can select text and copy it to
- the clipboard using command-C, or save it as a TeachText file.
-
- Pictures can be included in the text using the same scheme as
- TeachText: Each option-space character indicates where the top
- edge of a picture should go, and pictures are centered horizontally.
- Pictures come from consecutively-numbered PICT resources.
-
- A popup menu can be used to jump to "bookmarks", which are indicated
- by tab characters at ends of lines.
-
- Prototype:
-
- pascal void Show_help( short help_info_id,
- pascal void (*Handle_update)( WindowPtr ) );
-
- TO DO: error recovery, support for modeless use.
- */
-
-
-
- #ifndef NIL
- #define NIL 0L
- #endif
-
- #if ONE_RESOURCE
- #define GetResource Get1Resource
- #define CountResources Count1Resources
- #define GetNamedResource Get1NamedResource
- #endif ONE_RESOURCE
-
- #if ASSERTIONS
- #define ASSERT(x,y) if (!(x)) {DebugStr("\p" y);}
- #else
- #define ASSERT(x,y)
- #endif ASSERTIONS
-
- #if CHECKPOINTS
- #define CKPT(x) DebugStr( "\p" x )
- #else
- #define CKPT(x)
- #endif CHECKPOINTS
-
- enum {
- c_OK = 1, /* OK button */
- c_help, /* userItem for our help display */
- c_save, /* Button to save as TeachText */
- c_menu /* userItem for popup menu */
- };
-
- #define SCROLLBAR_WIDTH 16
- #define TEXT_INSET 4
-
- #define INITIAL_HIGHLIGHTS 8
-
-
-
- /* Prototypes of private routines
- */
- static pascal Boolean Help_filter( DialogPtr dialog,
- EventRecord *event, short *itemHit);
- static pascal void Text_userItem_proc( WindowPtr the_window, short item_num );
- static pascal void Menu_userItem_proc( WindowPtr the_window, short item_num );
- static pascal void Scroll_text( ControlHandle the_bar, short part_code );
- static pascal Auto_scroll( void );
- static void Handle_scroll( DialogPtr dialog,
- short the_part, Point local_point );
- static void Adjust_text( DialogPtr dialog );
- static void Save_text( TEHandle the_text, StringPtr default_filename );
- static void Topic_menu( DialogPtr dlog, MenuHandle help_popup );
- static MenuHandle Build_popup( TEHandle the_text, StringPtr default_menuname );
- static short Find_char(
- Handle data_h, // handle to a block of characters
- short offset, // initial offset within block
- char what ); // the character we're looking for
-
- #if COMPRESSION
- static Handle Get_compressed_resource( ResType the_type, short the_ID );
- static void Release_compressed_resource( Handle rsrc_h );
- static void Dispose_compressed_data( Handle the_handle );
- #else
- #define Get_compressed_resource GetResource
- #define Release_compressed_resource ReleaseResource
- #define Dispose_compressed_data(x)
- #endif
-
- #if USE_PICTS
- static void Find_pictures( DialogPtr dlog, short first_pict_id );
- static void Draw_picts( WindowPtr the_window, Rect *update_rect );
- static pascal void High_hook( Rect *high_rect );
- static void Do_deferred_hilites( help_ptr hptr, Rect *update_rect );
- static void Push_highlight( high_info **hh, Rect *rect );
- static Boolean Pop_highlight( high_info **hh, Rect *rect );
- #endif
-
- /* ------------------------- Show_help --------------------- );
- }
- asm {
- movem.L (SP)+, a1-a5/d1-d7
- moveQ #1, D0
- }
- }
-
- #if USE_PICTS
- /* ------------------------- Draw_picts --------------------------------- */
- /*
- Called by Adjust_text and Text_userItem_proc to draw pictures.
- */
- static void Draw_picts( WindowPtr the_window, Rect *update_rect )
- {
- register TEHandle the_text;
- register short pict_count, pict_index;
- PicHandle the_pict;
- short v_offset;
- Rect pict_loc, dummy;
-
- CKPT( "Draw_picts");
- the_text = (TEHandle) GetWRefCon( the_window );
- v_offset = (**the_text).destRect.top - (**the_text).viewRect.top
- - TEXT_INSET;
- pict_count = ((help_ptr) the_window)->pict_count;
- for (pict_index = 0; pict_index < pict_count; pict_index++)
- {
- pict_loc = ((help_ptr) the_window)->pict_data[pict_index].bounds;
- OffsetRect( &pict_loc, 0, v_offset );
- if (!SectRect( &pict_loc, update_rect, &dummy ))
- continue;
- the_pict = ((help_ptr) the_window)->pict_data[pict_index].pict;
- GetClip( ((help_ptr) the_window)->save_clip );
- ClipRect( update_rect );
- DrawPicture( the_pict, &pict_loc );
- SetClip( ((help_ptr) the_window)->save_clip );
- }
- }
-
- #define OPTION_SPACE_CHAR 0xCA
-
- /* ---------------------- Find_pictures ---------------------------- */
- static void Find_pictures( DialogPtr dlog, short first_pict_id )
- {
- register TEHandle the_text;
- Handle text_h;
- SignedByte text_state;
- register short offset;
- short num_picts;
- register short which_pict;
- pict_info *pict;
- Point place;
- short line_height, font_ascent;
- TextStyle what_style;
-
- CKPT( "Find_pictures");
- the_text = (TEHandle) GetWRefCon( dlog );
- text_h = (**the_text).hText;
- text_state = HGetState( text_h );
- HLock( text_h );
-
- /* Count option-space characters in the text. */
- offset = 0;
- num_picts = 0;
- offset = Find_char( text_h, offset, OPTION_SPACE_CHAR );
- while ( offset >= 0 )
- {
- num_picts++;
- offset++;
- offset = Find_char( text_h, offset, OPTION_SPACE_CHAR );
- }
-
- /* Allocate storage for an array of picture bounds. */
- pict = (pict_info *) NewPtr( sizeof(pict_info) * num_picts );
- ASSERT( pict != NIL, "NewPtr failed for pict_data" );
- ((help_ptr)dlog)->pict_data = pict;
-
- /*
- Initialize the picture info. For each picture we record the
- picture handle and its rectangle, in unscrolled window
- coordinates.
- */
- offset = 0;
- for (which_pict = 0; which_pict < num_picts; which_pict++)
- {
- pict[which_pict].pict = (PicHandle) Get_compressed_resource( 'PICT',
- first_pict_id + which_pict );
- if ( pict[which_pict].pict == NIL )
- break;
- offset = Find_char( text_h, offset, OPTION_SPACE_CHAR );
- place = TEGetPoint( offset, the_text );
- TEGetStyle( offset, &what_style, &line_height,
- &font_ascent, the_text );
- place.v -= line_height; /* align picture with TOP of option-space */
- offset++;
- pict[which_pict].bounds = (**pict[which_pict].pict).picFrame;
- OffsetRect( &pict[which_pict].bounds,
- ( ((**the_text).destRect.right + (**the_text).destRect.left) -
- (pict[which_pict].bounds.right + pict[which_pict].bounds.left)
- ) / 2,
- - pict[which_pict].bounds.top + place.v );
- }
- ((help_ptr)dlog)->pict_count = which_pict;
-
- getout:
- HSetState( text_h, text_state );
- }
- #endif /* USE_PICTS */
-
- /* ---------------------- Scroll_text ---------------------------- */
- /*
- This is used as a TrackControl actionProc for scrolling, and also
- called by Auto_scroll for automatic scrolling.
- */
- static pascal void Scroll_text( ControlHandle the_bar, short part_code )
- {
- register TEHandle the_text;
- register short delta;
- register WindowPtr the_display;
- short old_value;
- short offset, line;
- Point place;
- Rect view;
- TextStyle style;
- short line_height, font_ascent;
-
- CKPT( "Scroll_text");
- if (part_code != 0)
- {
- the_display = (**the_bar).contrlOwner;
- the_text = (TEHandle) GetWRefCon( the_display );
- view = (**the_text).viewRect;
- place.h = view.left + TEXT_INSET;
-
- switch (part_code)
- {
- case inUpButton:
- place.v = view.top;
- /*
- If we get the offset of the left edge of the top line,
- then subtract 1, we should have an offset belonging
- to the previous line.
- */
- offset = TEGetOffset( place, the_text ) - 1;
- if (offset == -1) offset = 0;
- place = TEGetPoint( offset, the_text );
- TEGetStyle( offset, &style, &line_height, &font_ascent,
- the_text );
- delta = place.v - line_height - view.top;
- break;
- case inDownButton:
- place.v = view.bottom + 2;
- offset = TEGetOffset( place, the_text );
- place = TEGetPoint( offset, the_text );
- /* Now place.v is at the baseline of the border line. */
- delta = place.v - view.bottom;
- break;
- case inPageUp:
- /*
- I want top border line to remain visible, and
- the top of a line should end up at view.top.
- */
- place.v = view.top + 2;
- offset = TEGetOffset( place, the_text );
- place = TEGetPoint( offset, the_text );
- /* place.v is at the baseline of the top border line. */
- TEGetStyle( offset, &style, &line_height, &font_ascent,
- the_text );
- place.v += line_height - font_ascent;
- place.v -= view.bottom - view.top;
- offset = TEGetOffset( place, the_text );
- place = TEGetPoint( offset, the_text );
- TEGetStyle( offset, &style, &line_height, &font_ascent,
- the_text );
- delta = place.v - view.top;
- if (offset == 0)
- delta -= line_height;
- break;
- case inPageDown:
- /*
- I want bottom border line to remain visible, and
- the bottom of a line should end up at view.bottom.
- */
- place.v = view.bottom - 2;
- offset = TEGetOffset( place, the_text );
- place = TEGetPoint( offset, the_text );
- /* place.v is at the baseline of the bottom border line. */
- TEGetStyle( offset, &style, &line_height, &font_ascent,
- the_text );
- place.v -= font_ascent; /* Top edge of bottom border line */
- place.v += view.bottom - view.top;
- /* We're looking at the bottom border of the next page. */
- offset = TEGetOffset( place, the_text );
- place = TEGetPoint( offset, the_text );
- TEGetStyle( offset, &style, &line_height, &font_ascent,
- the_text );
- delta = place.v - line_height - view.bottom;
- if (offset == (**the_text).teLength)
- delta += line_height;
- break;
- }
- old_value = GetCtlValue( the_bar );
- if ( ((delta < 0) && (old_value > 0)) ||
- ((delta > 0) && (old_value < GetCtlMax(the_bar))) )
- {
- /*
- When this routine is called, TextEdit may have set the
- clipping region to the view rectangle, so we reset it
- here to make sure the scroll bar gets drawn.
- */
- GetClip( ((help_ptr) the_display)->save_clip );
- ClipRect( &the_display->portRect );
- SetCtlValue( the_bar, old_value + delta );
- SetClip( ((help_ptr) the_display)->save_clip );
- }
- Adjust_text( the_display );
- }
- }
-
- /* ---------------------- Adjust_text ---------------------------- */
- /*
- Called by Handle_scroll and Scroll_text to scroll the text and
- pictures into sync with the scroll bar's control value.
- */
- static void Adjust_text( DialogPtr dialog )
- {
- register TEHandle the_text;
- register short scroll_down;
- short old_scroll;
- Rect update_rect;
-
- CKPT( "Adjust_text");
- the_text = (TEHandle) GetWRefCon( dialog );
- old_scroll = (**the_text).viewRect.top - (**the_text).destRect.top;
- scroll_down = old_scroll -
- GetCtlValue( ((help_ptr) dialog)->scrollbar );
- if (scroll_down == 0)
- return;
- #if USE_PICTS
- ((help_ptr) dialog)->high_defer_flag = true;
- //((help_ptr) dialog)->high_waiting = 0;
- #endif
- TEScroll( 0, scroll_down, the_text );
- #if USE_PICTS
- update_rect = (**the_text).viewRect;
- if (scroll_down > 0)
- {
- if (scroll_down < (update_rect.bottom - update_rect.top))
- update_rect.bottom = update_rect.top + scroll_down;
- }
- else
- if (- scroll_down < (update_rect.bottom - update_rect.top))
- update_rect.top = update_rect.bottom + scroll_down;
- Draw_picts( dialog, &update_rect );
- Do_deferred_hilites( (help_ptr) dialog, &update_rect );
- #endif
- }
-
-
- /* ---------------------- Handle_scroll ---------------------------- */
- /*
- Called by Help_filter to handle mouseDown events in the scroll bar.
- */
- static void Handle_scroll( DialogPtr dialog, short the_part, Point where )
- {
- register ControlHandle the_bar;
-
- CKPT( "Handle_scroll"); SetPort( dialog );
- the_bar = ((help_ptr) dialog)->scrollbar;
- if (the_part == inThumb)
- {
- (void) TrackControl( the_bar, where, NIL );
- Adjust_text( dialog );
- }
- else
- (void) TrackControl( the_bar, where, (ProcPtr)Scroll_text );
-
- }
-
- /* ---------------------- Help_filter ------------------------- */
- /*
- This is the dialog event filter for our help window.
- */
- #define RETURN_CHAR 0x0D
- #define TILDE_CHAR 0x7E
- #define ENTER_CHAR 0x03
- #define ESCAPE_CHAR 0x1B
-
- static pascal Boolean Help_filter( DialogPtr dialog,
- EventRecord *event, short *itemHit)
- {
- Point local_point;
- short the_part;
- ControlHandle the_control;
- short charcode;
- register TEHandle the_text;
- Rect item_box;
- short cursor;
- WindowPtr which_window;
- Boolean retval;
- RgnHandle gray_rgn;
- Rect gray_rect;
-
- retval = false; // usually, let the Dialog Mgr do further processing
- the_text = (TEHandle) GetWRefCon( dialog );
-
- GetMouse( &local_point );
- if (PtInRect( local_point, &(**the_text).viewRect ))
- SetCursor( *(((help_ptr) dialog)->ibeam_cursor) );
- else
- InitCursor();
- TEIdle( the_text );
-
- switch (event->what) {
- case nullEvent:
- break;
- case updateEvt:
- which_window = (WindowPtr) event->message;
- if ( (which_window != dialog) &&
- (((help_ptr)dialog)->Handle_update != NIL) )
- {
- (((help_ptr)dialog)->Handle_update)( which_window );
- retval = true; // done with this event
- }
- break;
- case mouseDown:
- CKPT( "Help_filter mousedown");
- the_part = FindWindow( event->where, &which_window );
- if (the_part == inMenuBar)
- {
- /*
- Calling MenuSelect lets one use the help and
- application menus.
- */
- (void) MenuSelect( event->where );
- retval = true; // get rid of the beep
- }
- else if ( (which_window == dialog) && (the_part == inContent) )
- {
- local_point = event->where;
- GlobalToLocal( &local_point );
- the_part = FindControl( local_point, dialog, &the_control );
- if (the_part && ((**the_control).contrlMax > 1) )
- {
- Handle_scroll( dialog, the_part, local_point );
- *itemHit = 2;
- retval = true;
- break;
- }
- else if (PtInRect( local_point, &(**the_text).viewRect ))
- {
- if (event->modifiers & shiftKey)
- TEClick( local_point, true, the_text );
- else
- TEClick( local_point, false, the_text );
- retval = true;
- }
- }
- else if ( (which_window == dialog) && (the_part == inDrag) )
- {
- gray_rgn = GetGrayRgn();
- gray_rect = (**gray_rgn).rgnBBox;
- DragWindow( dialog, event->where, &gray_rect );
- retval = true; // no beep
- }
- break;
- case keyDown :
- case autoKey :
- charcode = event->message & charCodeMask;
- /*
- There's no Cancel button, so we treat the OK button
- the same as a Cancel button.
- */
- if ( (charcode == RETURN_CHAR) || (charcode == ENTER_CHAR) ||
- (charcode == TILDE_CHAR) || (charcode == ESCAPE_CHAR) ||
- ((charcode == '.') && (event->modifiers & cmdKey)) )
- {
- *itemHit = c_OK; /* OK */
- Flash_button( dialog, *itemHit );
- retval = TRUE;
- }
- else if ( (charcode == 'c') && (event->modifiers & cmdKey) )
- {
- (void) ZeroScrap();
- TECopy( the_text );
- SystemEdit(3);
- local_point = (**the_text).selPoint;
- *(long *)&local_point = PinRect( &(**the_text).viewRect,
- local_point );
- cursor = TEGetOffset( local_point, the_text );
- TESetSelect( (long)cursor, (long)cursor, the_text );
- event->what = nullEvent;
- retval = true;
- }
- break;
- } /* end switch */
-
- return retval;
- }
-
-
- /* ---------------------- Text_userItem_proc ------------------------- */
- static pascal void Text_userItem_proc( WindowPtr the_window, short item_num )
- {
- Handle item_h;
- Rect item_box;
- short item_type;
- TEHandle the_text;
-
- CKPT( "Text_userItem_proc");
- the_text = (TEHandle) GetWRefCon( the_window );
- item_box = (**the_text).viewRect;
- #if USE_PICTS
- ((help_ptr) the_window)->high_defer_flag = true;
- #endif
- TEUpdate( &item_box, the_text );
-
- #if USE_PICTS
- Draw_picts( the_window, &item_box );
- Do_deferred_hilites( (help_ptr) the_window, &item_box );
- #endif
-
- /*
- Get the it